// I-interp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "math.h"
#include "malloc.h"
#include <conio.h>

#define WIDTH 1280
#define HEIGHT 720
#define ABS(x) ((x)>0 ? (x) : (-(x)))
#define MIN(a, b) ( (a)<(b) ? (a) : (b) )
#define SAME5(a, b, c, d, e) ( (a)==(b) && (b)==(c) && (c)==(d) && (d)==(e) )
#define SAME4(a, b, c, d) ( (a)==(b) && (b)==(c) && (c)==(d) )
#define SAME3(a, b, c) ( (a)==(b) && (b)==(c) )
#define SAME2(a, b) ( (a)==(b) )
#define NSAME(a, b) ( (a)!=(b) )

int DIFF2(int a, int b)
{
	int avg = (a+b+1)/2;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret = (ABS(ret)+1)*100/2;
	return ret;
}

int DIFF3(int a, int b, int c)
{
	int avg = (a+b+c+1)/3;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret += ABS(c-avg);
	ret = (ABS(ret)+1)*100/3;
	return ret;
}

int DIFF4(int a, int b, int c, int d)
{
	int avg = (a+b+c+d+2)/4;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret += ABS(c-avg);
	ret += ABS(d-avg);
	ret = (ABS(ret)+2)*100/4;
	return ret;
}

int DIFF5(int a, int b, int c, int d, int e)
{
	int avg = (a+b+c+d+e+2)/4;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret += ABS(c-avg);
	ret += ABS(d-avg);
	ret += ABS(e-avg);
	ret = (ABS(ret)+2)*100/5;
	return ret;
}

unsigned char *orig, *reco, *intp, *diff, *temp;
int intpmode[180][160];
int totaldirintp;
int correct = 0;
int error = 0;
int unchange = 0;

int innertable[128][4] = {	{0, 8, 8, 0}, // 0000000
							{6, 8, 8, 0}, // 0000001
							{0, 8, 8, 1}, // 0000010
							{6, 8, 8, 0}, // 0000011
							{0, 8, 8, 1}, // 0000100
							{0, 8, 8, 1}, // 0000101
							{4, 8, 8, 1}, // 0000110
							{4, 8, 8, 1}, // 0000111
							{4, 8, 8, 1}, // 0001000
							{8, 8, 8, 0}, // 0001001
							{8, 8, 8, 0}, // 0001010
							{8, 8, 8, 0}, // 0001011
							{8, 8, 8, 0}, // 0001100
							{8, 8, 8, 0}, // 0001101
							{8, 8, 8, 0}, // 0001110
							{8, 8, 8, 0}, // 0001111
							{8, 8, 8, 0}, // 0010000
							{8, 8, 8, 0}, // 0010001
							{8, 8, 8, 0}, // 0010010
							{8, 8, 8, 0}, // 0010011
							{8, 8, 8, 0}, // 0010100
							{8, 8, 8, 0}, // 0010101
							{8, 8, 8, 0}, // 0010110
							{8, 8, 8, 0}, // 0010111
							{8, 8, 8, 0}, // 0011000
							{8, 8, 8, 0}, // 0011001
							{8, 8, 8, 0}, // 0011010
							{8, 8, 8, 0}, // 0011011
							{8, 8, 8, 0}, // 0011100
							{8, 8, 8, 0}, // 0011101
							{8, 8, 8, 0}, // 0011110
							{8, 8, 8, 0}, // 0011111
							{8, 8, 8, 0}, // 0100000
							{8, 8, 8, 0}, // 0100001
							{8, 8, 8, 0}, // 0100010
							{8, 8, 8, 0}, // 0100011
							{8, 8, 8, 0}, // 0100100
							{8, 8, 8, 0}, // 0100101
							{8, 8, 8, 0}, // 0100110
							{8, 8, 8, 0}, // 0100111
							{8, 8, 8, 0}, // 0101000
							{8, 8, 8, 0}, // 0101001
							{8, 8, 8, 0}, // 0101010
							{8, 8, 8, 0}, // 0101011
							{8, 8, 8, 0}, // 0101100
							{8, 8, 8, 0}, // 0101101
							{8, 8, 8, 0}, // 0101110
							{8, 8, 8, 0}, // 0101111
							{8, 8, 8, 0}, // 0110000
							{8, 8, 8, 0}, // 0110001
							{8, 8, 8, 0}, // 0110010
							{8, 8, 8, 0}, // 0110011
							{8, 8, 8, 0}, // 0110100
							{8, 8, 8, 0}, // 0110101
							{8, 8, 8, 0}, // 0110110
							{8, 8, 8, 0}, // 0110111
							{8, 8, 8, 0}, // 0111000
							{8, 8, 8, 0}, // 0111001
							{8, 8, 8, 0}, // 0111010
							{8, 8, 8, 0}, // 0111011
							{8, 8, 8, 0}, // 0111100
							{8, 8, 8, 0}, // 0111101
							{8, 8, 8, 0}, // 0111110
							{8, 8, 8, 0}, // 0111111
							{8, 8, 8, 0}, // 1000000
							{8, 8, 8, 0}, // 1000001
							{8, 8, 8, 0}, // 1000010
							{8, 8, 8, 0}, // 1000011
							{8, 8, 8, 0}, // 1000100
							{8, 8, 8, 0}, // 1000101
							{8, 8, 8, 0}, // 1000110
							{8, 8, 8, 0}, // 1000111
							{8, 8, 8, 0}, // 1001000
							{8, 8, 8, 0}, // 1001001
							{8, 8, 8, 0}, // 1001010
							{8, 8, 8, 0}, // 1001011
							{8, 8, 8, 0}, // 1001100
							{8, 8, 8, 0}, // 1001101
							{8, 8, 8, 0}, // 1001110
							{8, 8, 8, 0}, // 1001111
							{8, 8, 8, 0}, // 1010000
							{8, 8, 8, 0}, // 1010001
							{8, 8, 8, 0}, // 1010010
							{8, 8, 8, 0}, // 1010011
							{8, 8, 8, 0}, // 1010100
							{8, 8, 8, 0}, // 1010101
							{8, 8, 8, 0}, // 1010110
							{8, 8, 8, 0}, // 1010111
							{8, 8, 8, 0}, // 1011000
							{8, 8, 8, 0}, // 1011001
							{8, 8, 8, 0}, // 1011010
							{8, 8, 8, 0}, // 1011011
							{8, 8, 8, 0}, // 1011100
							{8, 8, 8, 0}, // 1011101
							{8, 8, 8, 0}, // 1011110
							{8, 8, 8, 0}, // 1011111
							{8, 8, 8, 0}, // 1100000
							{8, 8, 8, 0}, // 1100001
							{8, 8, 8, 0}, // 1100010
							{8, 8, 8, 0}, // 1100011
							{8, 8, 8, 0}, // 1100100
							{8, 8, 8, 0}, // 1100101
							{8, 8, 8, 0}, // 1100110
							{8, 8, 8, 0}, // 1100111
							{8, 8, 8, 0}, // 1101000
							{8, 8, 8, 0}, // 1101001
							{8, 8, 8, 0}, // 1101010
							{8, 8, 8, 0}, // 1101011
							{8, 8, 8, 0}, // 1101100
							{8, 8, 8, 0}, // 1101101
							{8, 8, 8, 0}, // 1101110
							{8, 8, 8, 0}, // 1101111
							{8, 8, 8, 0}, // 1110000
							{8, 8, 8, 0}, // 1110001
							{8, 8, 8, 0}, // 1110010
							{8, 8, 8, 0}, // 1110011
							{8, 8, 8, 0}, // 1110100
							{8, 8, 8, 0}, // 1110101
							{8, 8, 8, 0}, // 1110110
							{8, 8, 8, 0}, // 1110111
							{8, 8, 8, 0}, // 1111000
							{8, 8, 8, 0}, // 1111001
							{8, 8, 8, 0}, // 1111010
							{8, 8, 8, 0}, // 1111011
							{8, 8, 8, 0}, // 1111100
							{8, 8, 8, 0}, // 1111101
							{8, 8, 8, 0}, // 1111110
							{8, 8, 8, 0}  // 1111111
/*			for (y=0; y<128; y++) {
				printf("%c %c %c\n", y&0x04?'.':'@', y&0x08?'.':'@', y&0x10?'.':'@');
				printf("%c   %c\n", y&0x02?'.':'@', y&0x20?'.':'@');
				printf("%c   %c\n", y&0x01?'.':'@', y&0x40?'.':'@');
				printf("--------%x\n", y);
				getch();
			}*/
};




int tryIntpMode(int mode, int xx, int yy, int* minsad)
{
	int m, n, x, y;
	int sad = 0;

	for (n=0; n<4; n++) {
		for (m=0; m<8; m+=2) {
			y = yy + n;
			x = xx + m;

			int a0 = intp[y*WIDTH+x-1];
			int a1, b0, b1, c0;

			if (x==1) a1 = a0;
			else a1 = intp[y*WIDTH+x-3];

			if (x==WIDTH-1) b0 = b1 = a0;
			else if (x==WIDTH-3) { b0 = intp[y*WIDTH+x+1]; b1 = b0; }
			else { b0 = intp[y*WIDTH+x+1]; b1 = intp[y*WIDTH+x+3]; }

			if (y<4) c0 = (a0+b0+1)/2;
			else c0 = reco[((y/4)*4-1)*WIDTH+x];

			switch(mode) {
				default:
				case 0:
					intp[y*WIDTH+x] = (-a1 + 9*a0 + 9*b0 + 0*c0 - b1 + 8) / 16;
					break;
				case 1:
					intp[y*WIDTH+x] = (-a1 + 5*a0 + 5*b0 + 0*c0 - b1 + 4) / 8;
					break;
				case 2:
					intp[y*WIDTH+x] = (a0 + b0 + 1) / 2;
					break;
				case 3:
					intp[y*WIDTH+x] = (-a1 + 8*a0 + 8*b0 + 2*c0 - b1 + 8) / 16;
					break;
				case 4:
					intp[y*WIDTH+x] = (-a1 + 6*a0 + 6*b0 + 6*c0 - b1 + 8) / 16;
					break;
				case 5:
					intp[y*WIDTH+x] = (-a1 + 2*a0 + 2*b0 + 14*c0 - b1 + 8) / 16;
					break;
				case 6:
					intp[y*WIDTH+x] = a0;
					break;
			}
			diff[y*WIDTH+x] = ABS(orig[y*WIDTH+x] - intp[y*WIDTH+x]);
			sad += diff[y*WIDTH+x];
		}
	}

	if (sad < *minsad) {
		*minsad = sad;
		return 1;
	} else {
		return 0;
	}
}

void mydirintp(int xx, int yy, int sad)
{
	int m, n, x, y;

	for (n=0; n<4; n++) {
		for (m=0; m<8; m+=2) {
			y = yy + n;
			x = xx + m + 1;

			int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15;
			int max, min; max = 0; min = 100000;
			a0 = reco[(y+1)*WIDTH+(x-1)]; if (a0>max) max=a0; if (a0<min) min=a0;
			a1 = reco[(y  )*WIDTH+(x-1)]; if (a1>max) max=a1; if (a1<min) min=a1;
			a2 = reco[(y-1)*WIDTH+(x-1)]; if (a2>max) max=a2; if (a2<min) min=a2;
			a3 = reco[(y-1)*WIDTH+(x  )]; if (a3>max) max=a3; if (a3<min) min=a3;
			a4 = reco[(y-1)*WIDTH+(x+1)]; if (a4>max) max=a4; if (a4<min) min=a4;
			a5 = reco[(y  )*WIDTH+(x+1)]; if (a5>max) max=a5; if (a5<min) min=a5;
			a6 = reco[(y+1)*WIDTH+(x+1)]; if (a6>max) max=a6; if (a6<min) min=a6;
			a7  = reco[(y  )*WIDTH+(x-2)]; if (a7>max) max=a7; if (a7<min) min=a7;
			a8  = reco[(y-1)*WIDTH+(x-2)]; if (a8>max) max=a8; if (a8<min) min=a8;
			a9  = reco[(y-2)*WIDTH+(x-2)]; if (a9>max) max=a9; if (a9<min) min=a9;
			a10 = reco[(y-2)*WIDTH+(x-1)]; if (a10>max) max=a10; if (a10<min) min=a10;
			a11 = reco[(y-2)*WIDTH+(x  )]; if (a11>max) max=a11; if (a11<min) min=a11;
			a12 = reco[(y-2)*WIDTH+(x+1)]; if (a12>max) max=a12; if (a12<min) min=a12;
			a13 = reco[(y-2)*WIDTH+(x+2)]; if (a13==0) a13=a12; if (a13>max) max=a13; if (a13<min) min=a13;
			a14 = reco[(y-1)*WIDTH+(x+2)]; if (a14==0) a14=a4; if (a14>max) max=a14; if (a14<min) min=a14;
			a15 = reco[(y  )*WIDTH+(x+2)]; if (a15==0) a15=a5; if (a15>max) max=a15; if (a15<min) min=a15;
			int avg = (a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+8)/16;

			int v = 0;
			int tv = 0;
			int b0, b1, b2, b3, b4, b5, b6, inner = 0;
			int b7, b8, b9, b10, b11, b12, b13, b14, b15, outter = 0;
			inner = (a0>avg) ? inner|1 : inner;		b0 = (a0>avg) ? 1 : 0;
			inner = (a1>avg) ? inner|2 : inner;		b1 = (a1>avg) ? 1 : 0;
			inner = (a2>avg) ? inner|4 : inner;		b2 = (a2>avg) ? 1 : 0;
			inner = (a3>avg) ? inner|8 : inner;		b3 = (a3>avg) ? 1 : 0;
			inner = (a4>avg) ? inner|16 : inner;	b4 = (a4>avg) ? 1 : 0;
			inner = (a5>avg) ? inner|32 : inner;	b5 = (a5>avg) ? 1 : 0;
			inner = (a6>avg) ? inner|64 : inner;	b6 = (a6>avg) ? 1 : 0;
			outter = (a7 >avg) ? outter|1 : outter;		b7 = (a7>avg) ? 1 : 0;
			outter = (a8 >avg) ? outter|2 : outter;		b8 = (a8>avg) ? 1 : 0;
			outter = (a9 >avg) ? outter|4 : outter;		b9 = (a9>avg) ? 1 : 0;
			outter = (a10>avg) ? outter|8 : outter;		b10 = (a10>avg) ? 1 : 0;
			outter = (a11>avg) ? outter|16 : outter;	b11 = (a11>avg) ? 1 : 0;
			outter = (a12>avg) ? outter|32 : outter;	b12 = (a12>avg) ? 1 : 0;
			outter = (a13>avg) ? outter|64 : outter;	b13 = (a13>avg) ? 1 : 0;
			outter = (a14>avg) ? outter|128 : outter;	b14 = (a14>avg) ? 1 : 0;
			outter = (a15>avg) ? outter|256 : outter;	b15 = (a15>avg) ? 1 : 0;

			int line, minline, line0, line1, line2, line3, line4, line5, line6, line7;
			int bshow = 0;
			tv = ( -a7 + 5*a1 + 5*a5 - a15 + 4 ) / 8;
			if (max-min<20) {
				v = tv;
			} else {
				line=0; minline = 100000;
				line0 = DIFF4(a7, a1, a5, a15); if (line0<minline) { minline=line0; line=0; }
				line1 = (DIFF4(a7, a1, a4, a14) + DIFF3(a0, a5, a15) + 1)/2; if (line1<minline) { minline=line1; line=1; }
				line2 = DIFF3(a0, a4, a13); if (line2<minline) { minline=line2; line=2; }
				line3 = (DIFF2(a4, a12) + DIFF3(a0, a3, a11) + 1)/2; if (line3<minline) { minline=line3; line=3; }
				line4 = (DIFF2(a3, a11) + MIN(DIFF4(a0, a1, a2, a10),DIFF4(a6, a5, a4, a12)) + 1)/2;  if (line4<minline) { minline=line4; line=4; }
				line5 = (DIFF2(a2, a10) + DIFF3(a6, a3, a11) + 1)/2; if (line5<minline) { minline=line5; line=5; }
				line6 = DIFF3(a6, a2, a9); if (line6<minline) { minline=line6; line=6; }
				line7 = (DIFF4(a8, a2, a5, a15) + DIFF3(a7, a1, a6) + 1)/2; if (line7<minline) { minline=line7; line=7; }

				// x x x
				// x   .
				// x   x
				if ( inner==0x20 || inner==0x5F ) {
					if ( SAME3(b2, b8, b14) ) {
						v = tv;
					} else if ( SAME3(b3, b10, b11) || SAME3(b3, b11, b12) ) {
						if ( SAME2(b5, b15) && SAME2(b1, b7) ) {
							v = tv;
						} else if ( NSAME(b5, b15) ) {
							v = ( a1 + a3 + a5 + 1 ) / 3;
						} else {
							v = ( -a11 + 3*a3 + a1 + a5 + 2) / 4;
						}
					} else {
						v = tv;///( a1 + a5 + 1 ) / 2;
					}
				// x x x
				// .   x
				// x   x
				} else if ( inner==0x02 || inner==0x7D ) {
					if ( SAME3(b2, b8, b14) ) {
						v = tv;
					} else if ( SAME3(b3, b10, b11) || SAME3(b3, b11, b12) ) {
						if ( SAME2(b5, b15) && SAME2(b1, b7) ) {
							v = tv;
						} else if ( NSAME(b1, b7) ) {
							v = ( a1 + a3 + a5 + 1 ) / 3;
						} else {
							v = ( -a11 + 3*a3 + a1 + a5 + 2) / 4;
						}
					} else {
						v = tv;
					}
				// x x .
				// x   .
				// x   .
				} else if ( inner==0x70 || inner==0x0F ) {
					if ( SAME3(b3, b10, b11) && SAME2(b4, b12) ) {
						v = a3 + (a5-a4+a1-a2)/2;
					} else {
						v = tv;
					}
				// . x x
				// .   x
				// .   x
				} else if ( inner==0x78 || inner==0x07 ) {
					if ( SAME3(b3, b11, b12) && SAME2(b2, b10) ) {
						v = a3 + (a5-a4+a1-a2)/2;
					} else {
						v = tv;
					}
				// x x x
				// x   x
				// .   .
				} else if ( inner==0x3E || inner==0x41 ) {
					if ( SAME3(b3, b10, b11) || SAME3(b3, b11, b12) ) {
						v = ( 1*tv + a3 + (a5-a4+a1-a2)/2 + 1 ) / 2;
					} else {
						v = tv;
					}
				// x x .
				// x   .
				// x   x
				} else if ( inner==0x30 || inner== 0x4F ) {
					if ( SAME5(b4, b12, b13, b14, b15) && SAME2(b3, b11) ) {
						v = a3 + (a5-a4+a1-a2)/2;
					} else {
						v = tv;
					}
				// . x x
				// .   x
				// x   x
				} else if ( inner==0x06 || inner== 0x79 ) {
					if ( SAME5(b2, b7, b8, b9, b10) && SAME2(b3, b11) ) {
						v = a3 + (a5-a4+a1-a2)/2;
					} else {
						v = tv;
					}
					if ( ABS(orig[y*WIDTH+x]-v) > ABS(orig[y*WIDTH+x]-tv) ) { 
						if ( ABS(orig[y*WIDTH+x]-v) > 10 ) { bshow = 0; }
						error ++; 
					} else if ( ABS(orig[y*WIDTH+x]-v) == ABS(orig[y*WIDTH+x]-tv) ) { 
						if ( ABS(orig[y*WIDTH+x]-v) > 20 ) { bshow = 0; }
						unchange ++;
					} else {
						correct ++;
					}
				} else {
					v = tv;
				}


			}

			intp[y*WIDTH+x] = v;
			diff[y*WIDTH+x] = ABS(orig[y*WIDTH+x] - intp[y*WIDTH+x]);
			if (bshow) {
				printf("0)%d, 1)%d, 2)%d, 3)%d, 4)%d, 5)%d, 6)%d, 7)%d\n", line0, line1, line2, line3, line4, line5, line6, line7);
				printf("%c %c %c %c %c  ===========>  ", b9?'.':'@', b10?'.':'@', b11?'.':'@', b12?'.':'@', b13?'.':'@');
				printf("%3d %3d %3d %3d %3d\n", a9, a10, a11, a12, a13);
				printf("%c %c %c %c %c  ===========>  ", b8?'.':'@', b2?'.':'@', b3?'.':'@', b4?'.':'@', b14?'.':'@');
				printf("%3d %3d %3d %3d %3d\n", a8, a2, a3, a4, a14);
				printf("%c %c   %c %c  ===========>  ", b7?'.':'@', b1?'.':'@', b5?'.':'@', b15?'.':'@');
				printf("%3d %3d<%3d>%3d %3d\n", a7, a1, v, a5, a15);
				printf("  %c   %c    ===========>  ", b0?'.':'@', b6?'.':'@');
				printf("    %3d     %3d    \n", a0, a6);
				printf("------line=%d----[%d, %d]------C:U:E=%d:%d:%d---orig=%d-std=%d--\n", line, m, n, correct,unchange,error, orig[y*WIDTH+x], tv);
				getch();
			}
		}
	}
	int newsad = 0;
	for (y=yy-4; y<yy+5; y++) {
		for (x=xx-4; x<xx+9; x++) {
			if (x>=xx && y>=yy && x%2==1) {
				newsad += diff[y*WIDTH+x];
			}
		}
	}
	if (0) {///newsad > sad) {
		for (y=yy-4; y<yy+5; y++) {
			for (x=xx-4; x<xx+9; x++) {
				printf("%3d ", intp[y*WIDTH+x]);
			}
			printf("\n");
			for (x=xx-4; x<xx+9; x++) {
				if (x>=xx && y>=yy && x%2==1) {
					printf("%3d ", orig[y*WIDTH+x]);
				} else {
					printf("    ");
				}
			}
			printf("\n");
		}
		printf("[%d, %d]--------------------new-sad = %d\n", xx, yy, newsad);
		getch();
	}

	return;
}

void dirintp(int sx, int sy)
{
	int minsad = 1000000;
	int x, y;

	// for up most 4x4 block line and left most 4x4 block column
	if (sy<4 || sx<4 || sy>=HEIGHT-4 || sx>=WIDTH-4) {
		tryIntpMode(0, sx+1, sy, &minsad);
		return;
	} else {

		tryIntpMode(0, sx+1, sy, &minsad);
		int sad = 0;
		for (y=sy-4; y<sy+4; y++) {
			for (x=sx-4; x<sx+8; x++) {
				if (x>=sx && y>=sy && x%2==1) {
					sad += diff[y*WIDTH+x];
				}
			}
		}

		if (1) {
			mydirintp(sx, sy, sad);
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	int y, x;
	FILE* origf = fopen("..\\shuttlestart_1280x720_I.yuv", "rb");
	FILE* recof = fopen("..\\shuttlestart_24_jm_rec_original.yuv", "rb");
	FILE* refef = fopen("..\\shuttlestart_640x720_I1P1.yuv", "rb");
	FILE* intpf = fopen("..\\shuttlestart_640x720_I9P1.yuv", "wb+");

	orig = (unsigned char*)malloc(WIDTH*HEIGHT);   // the original value of I picture
	reco = (unsigned char*)malloc(WIDTH*HEIGHT);   // the reconstruct value of I picture
	intp = (unsigned char*)malloc(WIDTH*HEIGHT);   // the interpolation result
	diff = (unsigned char*)malloc(WIDTH*HEIGHT);   // the difference between interpolation result and reconstruct value
	temp = (unsigned char*)malloc(WIDTH/2*HEIGHT);
	// initialize all the value of reco, intp, diff into 0
	for (y=0; y<HEIGHT; y++) {
		for (x=0; x<WIDTH; x++) {
			reco[y*WIDTH+x] = intp[y*WIDTH+x] = diff[y*WIDTH+x] = 0;
		}
	}

	// get the original value from file
	fread(orig, 1, WIDTH*HEIGHT, origf);

	// get the even coloumn of reconstruct value, and initial interpolation value from file
	fread(temp, 1, WIDTH/2*HEIGHT, recof);
	for (y=0; y<HEIGHT; y++) {
		for (x=0; x<WIDTH/2; x++) {
			reco[y*WIDTH+x*2] = temp[y*WIDTH/2+x];
			intp[y*WIDTH+x*2] = temp[y*WIDTH/2+x];
		}
	}
	// skip the reconstruct chrome value
	fread(temp, 1, WIDTH/2*HEIGHT/2, recof);
	// get the odd coloumn of reconstruct value from file
	fread(temp, 1, WIDTH/2*HEIGHT, recof);
	for (y=0; y<HEIGHT; y++) {
		for (x=0; x<WIDTH/2; x++) {
			reco[y*WIDTH+x*2+1] = temp[y*WIDTH/2+x];
		}
	}

	int totalmode[7] = {0, 0, 0, 0, 0, 0, 0};
	totaldirintp = 0;
	for (y=0; y<HEIGHT; y+=4) {
		for (x=0; x<WIDTH; x+=8) {
			dirintp(x, y);
		}
	}

	double total_psnr = 0;
	for (y=0; y<HEIGHT; y+=16) {
		for (x=0; x<WIDTH; x+=16) {
			int m, n;
			double psnr = 0;
			for (n=0; n<16; n++) {
				for (m=0; m<8; m++) {
					int loc = (y+n)*WIDTH + x+m*2;
					psnr += (double)(diff[loc+1])*(diff[loc+1]);
				}
			}
			total_psnr += psnr;
			psnr = 10*log10( (double)(255*255) / (psnr/(double)(128)));
			if (psnr<7) {
				for (n=0; n<16; n++) {
					for (m=0; m<8; m++) {
						int loc = (y+n)*WIDTH + x+m*2;
						printf("%3d ", orig[loc]);
						if (diff[loc+1]<10)	printf("    ");
						else				printf("%3d ", intp[loc+1]);
					}
					printf("\n");
					for (m=0; m<8; m++) {
						int loc = (y+n)*WIDTH + x+m*2;
						printf("    ");
						if (diff[loc+1]<10)	printf("    ");
						else				printf("%3d ", reco[loc+1]);
					}
					printf("\n");
				}
				printf( "[y=%d, x=%d]  mode=%d%d,%d%d,%d%d,%d%d  psnr=%f\n", y/16, x/16, intpmode[y/4][x/8], intpmode[y/4][x/8+1], intpmode[y/4+1][x/8], intpmode[y/4+1][x/8+1], intpmode[y/4+2][x/8], intpmode[y/4+2][x/8+1], intpmode[y/4+3][x/8], intpmode[y/4+3][x/8+1], psnr );
				getch();
			}
		}
	}

	total_psnr = 10*log10( (double)(255*255) / (total_psnr/(double)((WIDTH/2)*HEIGHT)));
	printf( "total psnr=%f,  total-dir-intp=%d,  C:U:E=%d:%d:%d\n", total_psnr, totaldirintp, correct, unchange, error );
	getch();

	fseek(refef, 0, SEEK_SET);
	fread(temp, 1, WIDTH/2*HEIGHT, refef);
	for (y=0; y<HEIGHT; y++) {
		for (x=0; x<WIDTH/2; x++) {
			temp[y*WIDTH/2+x] = intp[y*WIDTH+x*2+1];
		}
	}
	fwrite(temp, 1, WIDTH/2*HEIGHT, intpf);
	fread(temp, 1, WIDTH/2*HEIGHT/2, refef);
	fwrite(temp, 1, WIDTH/2*HEIGHT/2, intpf);

	fread(temp, 1, WIDTH/2*HEIGHT, refef);
	fwrite(temp, 1, WIDTH/2*HEIGHT, intpf);
	fread(temp, 1, WIDTH/2*HEIGHT/2, refef);
	fwrite(temp, 1, WIDTH/2*HEIGHT/2, intpf);

	fclose(intpf);
	fclose(refef);
	fclose(origf);
	fclose(recof);
	return 0;
}

